package edu.pku.sei.mdabase.infrastructure.metamodel;

import java.util.ArrayList;
import java.util.List;

import edu.pku.sei.mdabase.basictypes.OCLVoidValue;
import edu.pku.sei.mdabase.core.IDataType;
import edu.pku.sei.mdabase.infrastructure.graph.GraphNode;

public class MetaClass extends GraphNode<MetaReference,MetaModelGraph> implements IDataType ,MetaAttributedElement{
	private List<MetaClass> superTypes = null;
	private List<MetaAttribute> ownedAttributes;
	
	public String toString(){
		return "MetaClass("+getName()+")";
	}
	
	private String name;

	public void setName(String name) {
		this.name = name;
	}

	public String getName() {
		return name;
	}

	public List<MetaClass> getSuperTypes() {
		if(superTypes==null)
			superTypes = new ArrayList<MetaClass>();
		return superTypes;
	}
	
	public void addSuperType(MetaClass type){
		List<MetaClass> l = getSuperTypes();
		if(l.contains(type)==false)
			l.add(type);
	}
	
	@Override
	public boolean isA(IDataType type){
		if(type == this) return true;
		
		List<MetaClass> l = getSuperTypes();
		for(MetaClass t : l) {
			if(t.isA(type)) 
				return true;
		}
		
		return false;
	} 

	public boolean isPrimitive() {
		return false;
	}

	public void addAttribute(String name,IDataType type){
		addAttribute(name,type,OCLVoidValue.VOID);
	}
	public void addAttribute(String name,IDataType type,Object defaultValue){
		MetaAttribute att = new MetaAttribute();
		att.setName(name);
		att.setType(type);
		att.setDefaultValue(defaultValue);
		
		getOwnedAttributes().add(att);
	}
	
	public MetaAttribute getAttribute(String name){
		List<MetaAttribute> l = getAttributes();
		for(MetaAttribute a : l){
			if(a.getName().equals(name))
				return a;
		}
		
		return null;
	}
	
	private List<MetaReference> referencesCache = null;
	public List<MetaReference> getReferences(){
		if(referencesCache==null){
			referencesCache = new ArrayList<MetaReference>();
			List<MetaReference> l = null;
			l = this.getEdges();
			
			for(MetaReference e : l ) { 
				referencesCache.add(e);
			}
			
			List<MetaClass> supers = getSuperTypes();
			for(MetaClass t : supers){
				referencesCache.addAll(t.getReferences());
			}
		}
		
		return referencesCache;
	}

	public MetaReference findReferenceByName(String name){
		List<MetaReference> refs = getReferences();
		for(MetaReference ref : refs){
			if(ref.getName().equals(name))
				return ref;
		}
		
		return null;
	}
	

	public List<MetaAttribute> getOwnedAttributes() {
		if(ownedAttributes==null){
			ownedAttributes = new ArrayList<MetaAttribute>();
		}
		return ownedAttributes;
	}
	
	private List<MetaAttribute> attributesCache = null;
	public List<MetaAttribute> getAttributes(){
		if(attributesCache==null) {
			attributesCache = new ArrayList<MetaAttribute>();
			
			List<MetaAttribute> l = null;
			l = getOwnedAttributes();
			for(MetaAttribute a : l){
				if(attributesCache.contains(a)==false)
					attributesCache.add(a);
			}
			List<MetaClass> supers = getSuperTypes();
			for(MetaClass t : supers){
				l = t.getAttributes();
				for(MetaAttribute a : l){
					if(attributesCache.contains(a)==false)
						attributesCache.add(a);
				}
			}
			
		}
		
		
		return attributesCache;
	}
}
